package com.carpedil.shirodemo.common.shiro;

import com.carpedil.shirodemo.system.model.User;
import com.carpedil.shirodemo.system.service.IUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.Collection;
import java.util.Set;

/** @author Administrator */
public class UserRealm extends AuthorizingRealm {
  private static final Logger log = LoggerFactory.getLogger(UserRealm.class);
  @Lazy @Autowired private IUserService userService;

  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    log.info("从数据库读取用户权限");
    User user = (User) principalCollection.getPrimaryPrincipal();
    String username = user.getUsername();

    // 通过用户名获取用户角色信息
    Set<String> roles = userService.selectRoleNameByUserName(username);
    // 通过用户名获取用户操作权限
    Set<String> perms = userService.selectPermsByUserName(username);

    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    info.setRoles(roles);
    info.setStringPermissions(perms);
    return info;
  }

  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
      throws AuthenticationException {
    log.info("从数据库获取用户认证信息");
    // 获取当前登录用户的token
    UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    User user = userService.selectUserByUserName(token.getUsername());
    if (user == null) {
      // 返回null，shiro底层会抛出UnknownAccountException，证明没有这个用户名
      return null;
    }
    // 获取用户盐值
    ByteSource salt = ByteSource.Util.bytes(user.getSalt());

    return new SimpleAuthenticationInfo(user, user.getPassword(), salt, this.getName());
  }

  @Autowired private SessionDAO sessionDAO;

  public void clearAllAuthCache() {
    // 获取所有 session
    Collection<Session> sessions = sessionDAO.getActiveSessions();
    for (Session session : sessions) {
      // 获取 session 登录信息。
      Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
      if (obj instanceof SimplePrincipalCollection) {
        // 强转
        SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
        User user = new User();
        BeanUtils.copyProperties(spc.getPrimaryPrincipal(), user);
        this.doClearCache(spc);
      }
    }
  }
}
